package ms.unicorn.modellanguage;

import java.util.Map;
import java.util.TreeMap;

import ms.unicorn.Element;
import ms.unicorn.Entity;
import ms.unicorn.diagram.edit.commands.EntityCreateCommand;
import ms.unicorn.diagram.edit.parts.EntityNameTextEditPart;
import ms.unicorn.diagram.edit.parts.EntityStereotypeTextEditPart;
import ms.unicorn.diagram.part.UnicornDiagramEditorPlugin;
import ms.unicorn.diagram.part.UnicornVisualIDRegistry;
import ms.unicorn.ui.edit.parts.IEntityEditPart;
import ms.unicorn.ui.figures.EntityDiamondFigure;
import ms.unicorn.ui.figures.EntityOvalFigure;
import ms.unicorn.ui.figures.EntityPlateFigure;
import ms.unicorn.ui.layout.DockConstraint;
import ms.unicorn.ui.layout.DotNetLayout;
import ms.unicorn.util.FigureConstant;
import ms.unicorn.util.ViewUtil;

import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gmf.runtime.common.core.command.ICommand;
import org.eclipse.gmf.runtime.diagram.core.preferences.PreferencesHint;
import org.eclipse.gmf.runtime.diagram.ui.editpolicies.NonResizableEditPolicyEx;
import org.eclipse.gmf.runtime.diagram.ui.preferences.IPreferenceConstants;
import org.eclipse.gmf.runtime.draw2d.ui.figures.FigureUtilities;
import org.eclipse.gmf.runtime.draw2d.ui.figures.WrappingLabel;
import org.eclipse.gmf.runtime.emf.type.core.requests.CreateElementRequest;
import org.eclipse.gmf.runtime.gef.ui.figures.DefaultSizeNodeFigure;
import org.eclipse.gmf.runtime.notation.FontStyle;
import org.eclipse.gmf.runtime.notation.Node;
import org.eclipse.gmf.runtime.notation.NotationFactory;
import org.eclipse.gmf.runtime.notation.NotationPackage;
import org.eclipse.gmf.runtime.notation.Shape;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferenceConverter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.RGB;

public class LanguageEntityEditHeperAdvice extends LanguageElementEditHelperAdvice implements FigureConstant {	
	public static final LanguageEntityEditHeperAdvice DefaultInstance = new LanguageEntityEditHeperAdvice();

	public ICommand getCreationCommand(LanguageElement element,
			CreateElementRequest req) {
		return new EntityCreateCommand(req);
	}
	
	@Override
	public EditPolicy createPrimaryDragEditPolicy(Element element, EditPart editPart) {
		if (!isResizeable(element))
			return new NonResizableEditPolicyEx();
		return null;
	}
	
	protected boolean isResizeable(Element element) {
		LanguageElement langElement = LanguageRegistry.INSTANCE.getLanguageElement(element);
		if (langElement instanceof LanguageEntity)
			return ((LanguageEntity) langElement).isResizeable();
		return true;
	}

	protected Dimension getDefaultSize(Element element, int wHint, int hHint) {
		Dimension size = new Dimension(wHint, hHint);
		if (element != null) {
			LanguageElement languageElement = LanguageRegistry.INSTANCE.getLanguageElement(element);
			if (languageElement instanceof LanguageEntity)
				size = ((LanguageEntity) languageElement).getDefaultSize();
		}
		return size;
	}

	@Override
	public Map<String, IFigure> createFigures(EditPart context, Element element, EditPart elementEditPart) {
		
		IFigure figure, primaryShape, nameFigure, stereotypeFigure, contentPane;
		Map<String, IFigure> figures = new TreeMap<String, IFigure>();
		
		figure = createFigureElement(element, FIGURE_ELEMENT_PLATE, elementEditPart);
		primaryShape = createFigureElement(element, FIGURE_ELEMENT_PRIMARY_SHAPE, elementEditPart);
		nameFigure = createFigureElement(element, FIGURE_ELEMENT_NAME, elementEditPart);
		stereotypeFigure = createFigureElement(element, FIGURE_ELEMENT_STEREOTYPE, elementEditPart);
		contentPane = createFigureElement(element, FIGURE_ELEMENT_CONTENT_PANE, elementEditPart);
		
		if (primaryShape == null)
			primaryShape = figure;
		
		if (figure == null)
			figure = primaryShape;
		
		if (figure == null || primaryShape == null)
			return null;
		
		//figure.add(stereotypeFigure, BorderLayout.TOP)
		figures.put(FIGURE_ELEMENT_PLATE, figure);
		figures.put(FIGURE_ELEMENT_PRIMARY_SHAPE, primaryShape);
		figures.put(FIGURE_ELEMENT_NAME, nameFigure);
		figures.put(FIGURE_ELEMENT_STEREOTYPE, stereotypeFigure);
		figures.put(FIGURE_ELEMENT_CONTENT_PANE, contentPane);
		
		buildFigures(elementEditPart, element, elementEditPart, figures);
		
		return figures;
	}
	
	protected void buildFigures(EditPart context, Element element, EditPart elementEditPart, 
			Map<String, IFigure> figures) {
		IFigure figure = figures.get(FIGURE_ELEMENT_PLATE);
		IFigure primaryShape = figures.get(FIGURE_ELEMENT_PRIMARY_SHAPE);
		IFigure nameFigure = figures.get(FIGURE_ELEMENT_NAME);
		
		//figure.add(primaryShape, BorderLayout.CENTER);
		//figure.add(nameFigure, BorderLayout.BOTTOM);
		if (nameFigure != null)
			figure.add(nameFigure, new DockConstraint(DockConstraint.DOCK_TOP, 0, 20));
		figure.add(primaryShape, new DockConstraint(DockConstraint.DOCK_FILL, 0, 0));
	}

	/**
	 * Get figure type for an element
	 * @param element
	 * @return Return FIGURE_TYPE_xxx constant determining element's figure type.
	 */
	protected int getPrimaryFigureType(Element element) {
		int figType = FIGURE_TYPE_DEFAULT;
		
		if (element != null) {
			
			LanguageElement languageElement = LanguageRegistry.INSTANCE.getLanguageElement(element);
			if (languageElement instanceof LanguageEntity)
				figType = ((LanguageEntity) languageElement).getFigureType();
		}
		return figType;
	}

	protected IFigure createFigureElement(Element element, String figureElement, EditPart elementEditPart) {
		if (FIGURE_ELEMENT_PLATE.equalsIgnoreCase(figureElement)) {
			IFigure plate = new EntityPlateFigure(getDefaultSize(element, 40, 40),
					(IEntityEditPart) elementEditPart);
			plate.setLayoutManager(new DotNetLayout());
			return plate;
		}
		if (FIGURE_ELEMENT_PRIMARY_SHAPE.equalsIgnoreCase(figureElement)) {
			int figType = getPrimaryFigureType(element);
			IFigure figure = null;
			switch (figType) {
			case FIGURE_TYPE_DIAMOND:	
				figure = new EntityDiamondFigure();
				break;
			case FIGURE_TYPE_CIRLCE:
				figure = new EntityOvalFigure(true);
				break;
			default:
				return null;
			}
			LanguageElement e = LanguageRegistry.INSTANCE.getLanguageElement(element);
			for(DecoratorProxy decor: e.getDecorators())
				decor.createDecoration(figure);
			return figure;
		}
		if (FIGURE_ELEMENT_NAME.equalsIgnoreCase(figureElement)) {
			WrappingLabel label = new WrappingLabel(element.getName());
			return label;
		}
		if (FIGURE_ELEMENT_STEREOTYPE.equalsIgnoreCase(figureElement)) {
			String stereotype = element.getStereotype();
			WrappingLabel label = new WrappingLabel(stereotype);
			label.setVisible(stereotype != null && stereotype.length() > 0);
			return label;
		}
		return null;
	}
	
	@Override
	public View createView(IAdaptable semanticAdapter, View containerView, String semanticHint,
			int index, boolean persisted, PreferencesHint preferencesHint) {
		Element domainElement = (Element)getSemanticElement(semanticAdapter);
		if (domainElement instanceof Entity)
			return createNode((Entity)domainElement, containerView, semanticHint, 
					index, persisted, preferencesHint);
		return null;
	}
	
	protected Node createNode(Entity entity, View containerView, String semanticHint,
			int index, boolean persisted, PreferencesHint preferencesHint) {
		Shape node = NotationFactory.eINSTANCE.createShape();
		node.setLayoutConstraint(NotationFactory.eINSTANCE.createBounds());
				
		node.setType("ms.unicorn.Entity");
		
		ViewUtil.insertChildView(containerView, node, index, persisted);
		node.setElement(entity);
		ViewUtil.stampShortcut(containerView, node);
		// initializeFromPreferences 
		if (preferencesHint == null)
			preferencesHint = UnicornDiagramEditorPlugin.DIAGRAM_PREFERENCES_HINT;
		
		final IPreferenceStore prefStore = (IPreferenceStore) preferencesHint
				.getPreferenceStore();
	

		RGB lineRGB = PreferenceConverter.getColor(
				prefStore, IPreferenceConstants.PREF_LINE_COLOR);
		ViewUtil.setStructuralFeatureValue(node,
				NotationPackage.eINSTANCE.getLineStyle_LineColor(),
				FigureUtilities.RGBToInteger(lineRGB));
		FontStyle nodeFontStyle = (FontStyle) node
				.getStyle(NotationPackage.Literals.FONT_STYLE);
		if (nodeFontStyle != null) {
			FontData fontData = PreferenceConverter.getFontData(prefStore,
					IPreferenceConstants.PREF_DEFAULT_FONT);
			nodeFontStyle.setFontName(fontData.getName());
			nodeFontStyle.setFontHeight(fontData.getHeight());
			nodeFontStyle.setBold((fontData.getStyle() & SWT.BOLD) != 0);
			nodeFontStyle.setItalic((fontData.getStyle() & SWT.ITALIC) != 0);
			RGB fontRGB = PreferenceConverter
					.getColor(prefStore, IPreferenceConstants.PREF_FONT_COLOR);
			nodeFontStyle.setFontColor(FigureUtilities.RGBToInteger(fontRGB)
					.intValue());
		}
		RGB fillRGB = PreferenceConverter.getColor(
				prefStore, IPreferenceConstants.PREF_FILL_COLOR);
		ViewUtil.setStructuralFeatureValue(node,
				NotationPackage.eINSTANCE.getFillStyle_FillColor(),
				FigureUtilities.RGBToInteger(fillRGB));
		ViewUtil.createLabel(node,
				UnicornVisualIDRegistry
						.getType(EntityNameTextEditPart.VISUAL_ID));
		ViewUtil.createLabel(node,
				UnicornVisualIDRegistry
						.getType(EntityStereotypeTextEditPart.VISUAL_ID));
		return node;
	}

	public boolean acceptChildren(LanguageElement element) {
		return false;
	}
}
